/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.cmti.skeleton.web.controller;

import com.cmti.commons.entity.AuthenticationInfo;
import com.cmti.commons.exception.service.ServiceException;
import com.cmti.commons.util.EncryptUtil;
import com.cmti.commons.util.RequestEndSystemInfo;
import com.cmti.commons.util.StringUtils;
import com.cmti.commons.web.AuthenticationFilter;
import com.cmti.skeleton.dto.SysLogDto;
import com.cmti.skeleton.entity.SysLog;
import com.cmti.skeleton.entity.SysUser;
import com.cmti.skeleton.service.SysLogService;
import com.cmti.skeleton.service.UserService;
import com.cmti.skeleton.web.SysLogInterceptor;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mobile.device.DeviceUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ThemeResolver;
import org.springframework.web.servlet.support.RequestContextUtils;

/**
 *
 * @author Danny Lee
 */
@Controller
public class LoginController {

    private final Log log = LogFactory.getLog(getClass());
    @Autowired
    UserService userService;
    @Autowired
    SysLogService sysLogService;

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String loginForm(SysUser user) {
        return "login";
    }

    @Deprecated
//    @RequestMapping("/logout")
    public String logout(HttpSession session, HttpServletRequest request) {
        AuthenticationInfo authInfo = null;
        if (session != null) {
            authInfo = (AuthenticationInfo) session.getAttribute(AuthenticationFilter.AUTH_INFO);
            session.invalidate();
        }
        // 记录日志
        SysLogDto sysLog = new SysLogDto();
        sysLog.setType(SysLog.TYPE_SYSTEM);
        sysLog.setOperTime(new Date());
        if (authInfo != null) {
            sysLog.setOperatorId(authInfo.getId().intValue());
            sysLog.setLogContent("用户 " + authInfo.getAccount() + "（" + authInfo.getName() + "）登出系统");
        } else {
            // 各种原因登出失败，比如session已经过期
            sysLog.setOperatorId(0);
            sysLog.setLogContent("登出系统异常: 用户会话已过期!");
            sysLog.setResult(SysLog.RESULT_FAIL);
        }
        sysLog.setIp(RequestEndSystemInfo.getIpAddr(request));
        sysLogService.add(sysLog);

        return "redirect:/login";
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String doLogin(@RequestParam String codeInp, SysUser user, BindingResult bindResult,
            HttpServletRequest request, HttpSession session) {
        // 记录日志
        SysLogDto sysLog = SysLogInterceptor.generateSysLog(request, SysLog.TYPE_SYSTEM,
                "用户 " + user.getAccount() + " 尝试登录系统。");

//        验证码
        // 如果是移动设备，暂不处理验证码
        if (DeviceUtils.getCurrentDevice(request).isNormal()) {
            String code = (String) session.getAttribute("code");
            if (code == null || codeInp == null || codeInp.length() < 1 || !code.equalsIgnoreCase(codeInp)) {
                bindResult.addError(new ObjectError("sysUser", "验证码输入错误，请重新输入！"));
                sysLog.setResult(SysLog.RESULT_FAIL);
                sysLog.setLogContent(sysLog.getLogContent() + "验证码错误。");
                return "login";
            }
        }

        AuthenticationInfo authInfo = null;
        try {
            authInfo = userService.authenticate(user.getAccount(), user.getPassword());
        } catch (ServiceException e) {
            bindResult.addError(new ObjectError("sysUser", e.getMessage()));
            sysLog.setResult(SysLog.RESULT_FAIL);
            sysLog.setLogContent(sysLog.getLogContent() + e.getMessage());
            return "login";
        }

        if (authInfo == null) {
            bindResult.addError(new ObjectError("sysUser", "无法登录，请稍后重试！"));
            sysLog.setResult(SysLog.RESULT_FAIL);
            return "login";
        } else {
            // shiro login
            SecurityUtils.getSubject().login(new UsernamePasswordToken(authInfo.getAccount(), authInfo.getPassword()));
            // 生成权限树及导航菜单
            Map<String, List> map = userService.generateRightsAndMenu(authInfo);
            List rightsList = map.get("rightsList");
            authInfo.setRights(rightsList);
            List rightsTree = map.get("rightsTree");
            List navMenuTree = map.get("navMenuTree");

            session.setAttribute(AuthenticationFilter.AUTH_INFO, authInfo);
            session.setAttribute("rightsTree", rightsTree);
            session.setAttribute("navMenu", navMenuTree);

            return "redirect:/main";
        }
    }

    @RequestMapping("/navMenu")
    public void getNavMenu(Map model, HttpSession session) {
        model.put("navMenu", session.getAttribute("navMenu"));
    }

    /**
     * 进入主页面
     *
     * @return
     */
    @RequestMapping("/main")
    public String mainPage(HttpServletRequest request, ModelMap model) {
        ThemeResolver themeResolver = RequestContextUtils.getThemeResolver(request);
        model.put("themeName", themeResolver.resolveThemeName(request));
        return "main_tree";
//        return "main_accordion";
    }

    /**
     *
     * 验证旧密码是否输入有误
     *
     * @param session
     * @param map
     * @param pwd
     */
    @RequestMapping("/validateOldPwd")
    public void validateOldPwd(HttpSession session, ModelMap map, @RequestParam("pwd") String pwd) {
        //获取到用户编号
        SysUser user = (SysUser) session.getAttribute(AuthenticationFilter.AUTH_INFO);
        //旧密码是否输入错误
        if (StringUtils.isNotNull(pwd) && EncryptUtil.encryptMD5(pwd).equals(user.getPassword())) {
            map.put("result", true);
        } else {
            map.put("result", false);
            map.put("message", "原密码输入有误!");
        }
    }

    @RequestMapping("/modifypwd")
    public void modifyPassword(HttpSession session, HttpServletRequest request, ModelMap map, @RequestParam("pwd") String pwd,
            @RequestParam("newPwd") String newPwd, @RequestParam("confirmedPwd") String confirmedPwd) {
        //获取到用户编号
        SysUser user = (SysUser) session.getAttribute(AuthenticationFilter.AUTH_INFO);
        // 准备日志实例
        StringBuilder logContent = new StringBuilder();
        logContent.append("用户 ").append(user.getAccount()).append("(")
                .append(user.getName()).append(") 进行了修改密码的操作");
        SysLog sysLog = SysLogInterceptor.generateSysLog(request, SysLog.TYPE_OPERATE, logContent.toString());
        //旧密码是否输入错误
        if (StringUtils.isNotNull(pwd) && EncryptUtil.encryptMD5(pwd).equals(user.getPassword())) {
            if (newPwd.equals(confirmedPwd)) {
                userService.resetPassword(user.getId(), newPwd);
                // Session中的user也同步改过来
                user.setPassword(EncryptUtil.encryptMD5(newPwd));
                map.addAttribute("result", true);
            } else {
                sysLog.setResult(SysLog.RESULT_FAIL);
                map.addAttribute("result", false).addAttribute("message", "两次密码输入不一致!");
            }
        } else {
            sysLog.setResult(SysLog.RESULT_FAIL);
            map.put("result", false);
            map.put("message", "原密码输入有误!");
        }
    }

}
